/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "../../User/Lcd_Driver.h"
#include "../../User/QDTFT_demo.h"
#include "../../User/my_define.h"
#include "../../User/ds18b20.h"
#include "../../User/pid.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;

TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;
TIM_HandleTypeDef htim8;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_TIM2_Init(void);
static void MX_TIM1_Init(void);
static void MX_TIM3_Init(void);
static void MX_TIM8_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void set_pwm_duty(float duty)
{
  static uint32_t period = 0;
  static uint32_t pulse  = 0;
  if(machine.choose_x == 5)
  {
    period = __HAL_TIM_GET_AUTORELOAD(&htim3) + 1;
    pulse  = (uint32_t)(duty * period);
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, pulse);
  }
  else if(machine.choose_x == 4)
  {
    period = __HAL_TIM_GET_AUTORELOAD(&htim1) + 1;
    pulse  = (uint32_t)(duty * period);
    __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pulse);
  }
  else if(machine.choose_x == 3)
  {
    period = __HAL_TIM_GET_AUTORELOAD(&htim1) + 1;
    pulse  = (uint32_t)(duty * period);
    __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, pulse);
  }
  else if(machine.choose_x == 6)
  {
    period = __HAL_TIM_GET_AUTORELOAD(&htim8) + 1;
    pulse  = (uint32_t)(duty * period);
    __HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_2, pulse);
  }
  else if(machine.choose_x == 1)
  {
    period = __HAL_TIM_GET_AUTORELOAD(&htim8) + 1;
    pulse  = (uint32_t)(duty * period);
    __HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_3, pulse);
  }
  else if(machine.choose_x == 2)
  {
    period = __HAL_TIM_GET_AUTORELOAD(&htim8) + 1;
    pulse  = (uint32_t)(duty * period);
    __HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_4, pulse);
  }
}
void ds18b20_delay_us(uint32_t us)
{
    htim2.Instance->CNT = 0;
    while (htim2.Instance->CNT < us)
        ;
}
// void set_current_duty_var()
// {

// }
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if(GPIO_Pin == knob_a_Pin)
  {
    ds18b20_delay_us(2000);
    if(HAL_GPIO_ReadPin(knob_a_GPIO_Port, knob_a_Pin) == GPIO_PIN_RESET &&
       HAL_GPIO_ReadPin(knob_b_GPIO_Port, knob_b_Pin) == GPIO_PIN_SET)
    {
      // *machine.duty_x += 0.1;
      // if(*machine.duty_x > 1.0)
      // {
      //   *machine.duty_x = 1.0;
      // }
      // set_pwm_duty(*machine.duty_x);
      if(machine.set_x == 1)
      {
        machine.set1++;
        if(machine.set1 > 99)
        {
          machine.set1 = 99;
        }
      }
      else if(machine.set_x == 2)
      {
        machine.set2++;
        if(machine.set2 > 99)
        {
          machine.set2 = 99;
        }
      }
      else if(machine.set_x == 3)
      {
        machine.set3++;
        if(machine.set3 > 99)
        {
          machine.set3 = 99;
        }
      }
      else if(machine.set_x == 4)
      {
        machine.set4++;
        if(machine.set4 > 99)
        {
          machine.set4 = 99;
        }
      }
      else if(machine.set_x == 5)
      {
        machine.set5++;
        if(machine.set5 > 99)
        {
          machine.set5 = 99;
        }
      }
      else if(machine.set_x == 6)
      {
        machine.set6++;
        if(machine.set6 > 99)
        {
          machine.set6 = 99;
        }
      }
      
    }
		__HAL_GPIO_EXTI_CLEAR_IT(knob_a_Pin);
    __HAL_GPIO_EXTI_CLEAR_IT(knob_b_Pin);
  }
  else if(GPIO_Pin == knob_b_Pin)
  {
    ds18b20_delay_us(2000);
    if(HAL_GPIO_ReadPin(knob_b_GPIO_Port, knob_b_Pin) == GPIO_PIN_RESET &&
       HAL_GPIO_ReadPin(knob_a_GPIO_Port, knob_a_Pin) == GPIO_PIN_SET)
    {
      // *machine.duty_x -= 0.1;
      // if(*machine.duty_x < 0.0)
      // {
      //   *machine.duty_x = 0.0;
      // }
      // set_pwm_duty(*machine.duty_x);
      if(machine.set_x == 1)
      {
        machine.set1--;
        if(machine.set1 < -9)
        {
          machine.set1 = -9;
        }
      }
      else if(machine.set_x == 2)
      {
        machine.set2--;
        if(machine.set2 < -9)
        {
          machine.set2 = -9;
        }
      }
      else if(machine.set_x == 3)
      {
        machine.set3--;
        if(machine.set3 < -9)
        {
          machine.set3 = -9;
        }
      }
      else if(machine.set_x == 4)
      {
        machine.set4--;
        if(machine.set4 < -9)
        {
          machine.set4 = -9;
        }
      }
      else if(machine.set_x == 5)
      {
        machine.set5--;
        if(machine.set5 < -9)
        {
          machine.set5 = -9;
        }
      }
      else if(machine.set_x == 6)
      {
        machine.set6--;
        if(machine.set6 < -9)
        {
          machine.set6 = -9;
        }
      }
    }
		__HAL_GPIO_EXTI_CLEAR_IT(knob_a_Pin);
    __HAL_GPIO_EXTI_CLEAR_IT(knob_b_Pin);
  }
  else if(GPIO_Pin == knob_push_Pin)
  {
    ds18b20_delay_us(2000);
    if(HAL_GPIO_ReadPin(knob_push_GPIO_Port, knob_push_Pin) == GPIO_PIN_RESET)
    {
      	// machine.choose_x++;
        // if(machine.choose_x > machine.choose_max)
        // {
        //   machine.choose_x = 1;
        // }
        // switch(machine.choose_x)
        // {
        //   case 1:
        //     machine.duty_x = &machine.duty1;
        //     break;
        //   case 2:
        //     machine.duty_x = &machine.duty2;
        //     break;
        //   case 3:
        //     machine.duty_x = &machine.duty3;
        //     break;
        //   case 4:
        //     machine.duty_x = &machine.duty4;
        //     break;
        //   case 5:
        //     machine.duty_x = &machine.duty5;
        //     break;
        //   case 6:
        //     machine.duty_x = &machine.duty6;
        //     break;
        // }
        if(machine.mode == MODE_SETTING)
        {
          machine.set_x++;
          if(machine.set_x > 6)
          {
            machine.set_x = 1;
          }
        }
    }
  }
  else if(GPIO_Pin == key_0_Pin)
  {
    ds18b20_delay_us(2000);
    if(HAL_GPIO_ReadPin(key_0_GPIO_Port, key_0_Pin) == GPIO_PIN_RESET)
    {
      	if(machine.mode == MODE_ON)
        {
          machine.mode = MODE_SETTING;
        }
        else
        {
          machine.mode = MODE_ON;
        }
    }
  }
}
void auto_control(int choose_x, float* set_x, float* read_x, float* duty_x)
{
  // 6 independent PID controllers and timebases (index 1..6)
  static PIDController pids[7];
  static uint8_t pid_inited[7] = {0};
  static uint32_t last_ms_arr[7] = {0};
  
  int idx = choose_x;
  if (idx < 1 || idx > 6) {
    idx = 1;
  }

  if (!pid_inited[idx])
  {
    // Common initial gains; adjust as needed per channel
    PID_Init(&pids[idx],
             0.6f,   // Kp
             0.2f,   // Ki
             0.05f,  // Kd
             0.001f, // out_min (duty lower bound)
             1.0f,   // out_max (duty upper bound)
             -1.0f,  // integrator_min
             1.0f);  // integrator_max

    // Make response slower and smoother:
    // - measurement LPF tau ~ 1.0s (collect more data)
    // - output LPF tau ~ 2.0s (slowly change)
    // - limit duty slope to 0.15 per second
    PID_ConfigFilter(&pids[idx], 1.0f, 2.0f);
    PID_ConfigSlew(&pids[idx], 0.15f);
    pid_inited[idx] = 1;
  }

  machine.choose_x = idx;

  uint32_t now = HAL_GetTick();
  float dt = (last_ms_arr[idx] == 0) ? 0.01f : ((now - last_ms_arr[idx]) / 1000.0f);
  if (dt <= 0.0f) dt = 0.001f;
  last_ms_arr[idx] = now;

  float duty = PID_Compute(&pids[idx], *set_x, *read_x, dt);

  // Smoothly apply or directly set
  *duty_x = duty;
  if (*duty_x < 0.001f) *duty_x = 0.001f;
  if (*duty_x > 1.0f)   *duty_x = 1.0f;

  set_pwm_duty(*duty_x);
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */
  static int i = 0;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_TIM2_Init();
  MX_TIM1_Init();
  MX_TIM3_Init();
  MX_TIM8_Init();
  /* USER CODE BEGIN 2 */
  Lcd_Init();
	HAL_TIM_Base_Start(&htim2);
	HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_4);
	HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_3);
	HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_2);
	machine.choose_x= 6;
	set_pwm_duty(machine.duty6);
  machine.choose_x = 5;
  set_pwm_duty(machine.duty5);
  machine.choose_x = 4;
  set_pwm_duty(machine.duty4);
  machine.choose_x = 3;
  set_pwm_duty(machine.duty3);
  machine.choose_x = 2;
  set_pwm_duty(machine.duty2);
  machine.choose_x = 1;
  set_pwm_duty(machine.duty1);
  Lcd_Clear(BLACK);
  LCD_LED_SET;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

      HAL_ADC_Start(&hadc1);
      HAL_ADC_PollForConversion(&hadc1, 50);
      machine.adc1 = HAL_ADC_GetValue(&hadc1);
      HAL_ADC_Start(&hadc1);
      HAL_ADC_PollForConversion(&hadc1, 50);
      machine.adc2 = HAL_ADC_GetValue(&hadc1);
      HAL_ADC_Start(&hadc1);
      HAL_ADC_PollForConversion(&hadc1, 50);
      machine.adc3 = HAL_ADC_GetValue(&hadc1);
      HAL_ADC_Start(&hadc1);
      HAL_ADC_PollForConversion(&hadc1, 50);
      machine.adc4 = HAL_ADC_GetValue(&hadc1);
      HAL_ADC_Start(&hadc1);
      HAL_ADC_PollForConversion(&hadc1, 50);
      machine.adc5 = HAL_ADC_GetValue(&hadc1);      
      HAL_ADC_Start(&hadc1);
      HAL_ADC_PollForConversion(&hadc1, 50);
      machine.adc6 = HAL_ADC_GetValue(&hadc1);
      machine.read1 = -0.01*machine.adc1+48.9;
      machine.read2 = -0.01*machine.adc2+48.9;
      machine.read3 = -0.01*machine.adc3+48.9;
      machine.read4 = -0.01*machine.adc4+48.9;
      machine.read5 = -0.01*machine.adc5+48.9;
      machine.read6 = -0.01*machine.adc6+48.9;
      if(machine.read1 < -90.0)
      {
        machine.read1 = -90.0;
      }
      if(machine.read2 < -90.0)
      {
        machine.read2 = -90.0;
      }
      if(machine.read3 < -90.0)
      {
        machine.read3 = -90.0;
      }
      if(machine.read4 < -90.0)
      {
        machine.read4 = -90.0;
      }
      if(machine.read5 < -90.0)
      {
        machine.read5 = -90.0;
      }
      if(machine.read6 < -90.0)
      {
        machine.read6 = -90.0;
      }
      if(machine.read1 > 90.0)
      {
        machine.read1 = 90.0;
      }
      if(machine.read2 > 90.0)
      {
        machine.read2 = 90.0;
      }
      if(machine.read3 > 90.0)
      {
        machine.read3 = 90.0;
      }
      if(machine.read4 > 90.0)
      {
        machine.read4 = 90.0;
      }
      if(machine.read5 > 90.0)
      {
        machine.read5 = 90.0;
      }
      if(machine.read6 > 90.0)
      {
        machine.read6 = 90.0;
      }
      HAL_ADC_Stop(&hadc1);
      auto_control(1, &machine.set1, &machine.read1, &machine.duty1);
      auto_control(2, &machine.set2, &machine.read2, &machine.duty2);
      auto_control(3, &machine.set3, &machine.read3, &machine.duty3);
      auto_control(4, &machine.set4, &machine.read4, &machine.duty4);
      auto_control(5, &machine.set5, &machine.read5, &machine.duty5);
      auto_control(6, &machine.set6, &machine.read6, &machine.duty6);
      machine.ds18b20_x10 = DS18B20_Get_Temp();
      machine.ds18b20_tempture = machine.ds18b20_x10 / 10.0;
      QDTFT_loop();
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief ADC1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_ADC1_Init(void)
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */

  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ENABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = ENABLE;
  hadc1.Init.NbrOfDiscConversion = 1;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 6;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_2;
  sConfig.Rank = 2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_3;
  sConfig.Rank = 3;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = 4;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_5;
  sConfig.Rank = 5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_6;
  sConfig.Rank = 6;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */

}

/**
  * @brief TIM1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM1_Init(void)
{

  /* USER CODE BEGIN TIM1_Init 0 */

  /* USER CODE END TIM1_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

  /* USER CODE BEGIN TIM1_Init 1 */

  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 168-1;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 1000-1;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 500;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */

  /* USER CODE END TIM1_Init 2 */
  HAL_TIM_MspPostInit(&htim1);

}

/**
  * @brief TIM2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 168-1;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 429496725;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */

}

/**
  * @brief TIM3 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 168-1;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 1000-1;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 500;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */

  /* USER CODE END TIM3_Init 2 */
  HAL_TIM_MspPostInit(&htim3);

}

/**
  * @brief TIM8 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM8_Init(void)
{

  /* USER CODE BEGIN TIM8_Init 0 */

  /* USER CODE END TIM8_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

  /* USER CODE BEGIN TIM8_Init 1 */

  /* USER CODE END TIM8_Init 1 */
  htim8.Instance = TIM8;
  htim8.Init.Prescaler = 168-1;
  htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim8.Init.Period = 1000-1;
  htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim8.Init.RepetitionCounter = 0;
  htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim8) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim8) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 500;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
  {
    Error_Handler();
  }
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM8_Init 2 */

  /* USER CODE END TIM8_Init 2 */
  HAL_TIM_MspPostInit(&htim8);

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  /* USER CODE BEGIN MX_GPIO_Init_1 */

  /* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8|GPIO_PIN_9, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_5
                          |GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);

  /*Configure GPIO pins : PE8 PE9 */
  GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

  /*Configure GPIO pins : key_0_Pin knob_push_Pin knob_a_Pin knob_b_Pin */
  GPIO_InitStruct.Pin = key_0_Pin|knob_push_Pin|knob_a_Pin|knob_b_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : PB13 PB14 PB15 PB5
                           PB6 PB7 */
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_5
                          |GPIO_PIN_6|GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);

  HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

  /* USER CODE BEGIN MX_GPIO_Init_2 */

  /* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
